package core

import (
	"craft/core/ast"
	"craft/core/token"
	"errors"
	"fmt"
	"strconv"
)

type Calculator struct {
}

func (c *Calculator) IntDeclare(tokens *token.Tokens) (*ast.SimpleASTNode, error) {
	var _node *ast.SimpleASTNode = nil
	_token := tokens.Peek()

	// 判断是 Int 定义
	if _token != nil && _token.Type == token.Int {
		_token = tokens.Read()
		if tokens.Peek().Type == token.Identifier {
			_token = tokens.Read()
			_node = ast.NewSimpleASTNode(ast.IntDeclaration, _token.Content)
			_token = tokens.Peek()
			if _token != nil && _token.Type == token.Assignment {
				_ = tokens.Read()                //消耗掉等号
				child, err := c.Additive(tokens) //匹配一个表达式
				if err != nil {
					return nil, err
				} else if child == nil {
					return nil, errors.New("变量初始化，需要有计算表达式 ")
				} else {
					_node.AddChild(child)
				}
			}
		} else {
			return nil, errors.New(" 需要定义变量名！ ")
		}

	}
	return _node, nil
}

func (c *Calculator) Additive(tokens *token.Tokens) (*ast.SimpleASTNode, error) {

	var _err error
	var _child1, _child2 *ast.SimpleASTNode

	_child1, _err = c.Multiplicative(tokens)
	if _err != nil {
		return nil, _err
	}

	_node := _child1
	_token := tokens.Peek()
	if _child1 != nil && _token != nil {
		if _token.Type == token.Plus || _token.Type == token.Minus {
			_token = tokens.Read()

			_child2, _err = c.Additive(tokens)
			if _err != nil {
				return nil, _err
			}

			if _child2 != nil {
				_node = ast.NewSimpleASTNode(ast.Additive, _token.Content)
				_node.AddChild(_child1)
				_node.AddChild(_child2)
			} else {
				return nil, errors.New("加法/减法 表达式 需要右边有一个表达式")
			}
		}
	}

	return _node, nil
}

func (c *Calculator) Multiplicative(tokens *token.Tokens) (*ast.SimpleASTNode, error) {
	var _child1, _child2 *ast.SimpleASTNode
	var _err error
	_child1, _err = c.Primary(tokens)
	if _err != nil {
		return nil, _err
	}

	_node := _child1

	_token := tokens.Peek()
	if _child1 != nil && _token != nil {
		if _token.Type == token.Star || _token.Type == token.Slash {
			_token = tokens.Read()

			_child2, _err = c.Multiplicative(tokens)
			if _err != nil {
				return nil, _err
			}

			if _child2 != nil {
				_node = ast.NewSimpleASTNode(ast.Multiplicative, _token.Content)
				_node.AddChild(_child1)
				_node.AddChild(_child2)
			} else {
				return nil, errors.New("乘法/除法 表达式 需要右边有一个表达式")
			}
		}
	}

	return _node, nil
}

func (c *Calculator) Primary(tokens *token.Tokens) (*ast.SimpleASTNode, error) {
	var _node *ast.SimpleASTNode
	_token := tokens.Peek()
	if _token != nil {
		if _token.Type == token.IntLiteral {
			_token = tokens.Read()
			_node = ast.NewSimpleASTNode(ast.IntLiteral, _token.Content)
		} else if _token.Type == token.Identifier {
			_token = tokens.Read()
			_node = ast.NewSimpleASTNode(ast.Identifier, _token.Content)
		}
	}
	return _node, nil
}

func (c *Calculator) Evaluate(node ast.SimpleASTNode, indent string) int {
	_result := 0

	var child1, child2 ast.SimpleASTNode
	var value1, value2 int

	fmt.Println(indent + "Calculating: " + node.GetType().String())
	switch node.GetType() {
	case ast.Programme:
		for _, _child := range node.GetChildren() {
			_result = c.Evaluate(_child, indent+"\t")
		}
	case ast.Additive:
		child1 = node.GetChildren()[0]
		value1 = c.Evaluate(child1, indent+"\t")
		child2 = node.GetChildren()[1]
		value2 = c.Evaluate(child2, indent+"\t")
		if node.GetText() == "+" {
			_result = value1 + value2
		} else {
			_result = value1 - value2
		}
	case ast.Multiplicative:
		child1 = node.GetChildren()[0]
		value1 = c.Evaluate(child1, indent+"\t")
		child2 = node.GetChildren()[1]
		value2 = c.Evaluate(child2, indent+"\t")
		if node.GetText() == "*" {
			_result = value1 * value2
		} else {
			_result = value1 / value2
		}
	case ast.IntLiteral:
		_result, _ = strconv.Atoi(node.GetText())
	default:
	}
	fmt.Printf("%s %d\n", indent+"Result: ", _result)
	return _result
}
